package com.atguigu.service.impl;

import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.AsyncCartInfoService;
import com.atguigu.service.CartInfoService;
import com.atguigu.util.AuthContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoService asyncCartInfoService;

    @Override
    public void addToCart(String oneOfUserId, Long skuId, Integer skuNum) {
        //查询数据库
        CartInfo cartInfo = getCartInfoFromDb(oneOfUserId, skuId);
        if (cartInfo != null) {
            //修改
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            cartInfo.setCartPrice(skuPrice);
            baseMapper.updateById(cartInfo);
        } else {
            //c.如果不存在 新增一条记录
            cartInfo = new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setUserId(oneOfUserId);
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setSkuNum(skuNum);
            //默认设置勾选该商品
            cartInfo.setIsChecked(1);
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            baseMapper.insert(cartInfo);
            //asyncCartInfoService.saveCartInfo(cartInfo);
        }

        //在缓存里存一份
        String userCartKey = getUserCartKey(oneOfUserId);
        redisTemplate.boundHashOps(userCartKey).put(skuId.toString(), cartInfo);

    }


    @Override
    public List<CartInfo> getCartList(HttpServletRequest request) {
        //未登录
        String userTempId = AuthContextHolder.getUserTempId(request);
        String userId = AuthContextHolder.getUserId(request);
        List<CartInfo> CartInfoData = new ArrayList<>();
        if (StringUtils.isEmpty(userId) && !StringUtils.isEmpty(userTempId)) {
            CartInfoData = queryDataFromCash(userTempId);
        }
        //已登录
        if (!StringUtils.isEmpty(userId)) {
            //遍历未登录得信息
            List<CartInfo> noLoginCartInfo = queryDataFromCash(userTempId);
            //skuId相同的进行合并,并删除临时得数据信息,把临时id 改为userId,skuNum数量相加
            if (!CollectionUtils.isEmpty(noLoginCartInfo)) {
                //合并数据
                margeCartInfo(userId, userTempId);
                //删除数据,userId,userTempId
                CartInfoData = deleteNoLoginDataAndReload(userId, userTempId);
            } else {
                CartInfoData = queryDataFromCash(userId);
            }
        }
        return CartInfoData;
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked, String oneOfUserId) {

        List<Integer> list = new ArrayList<Integer>();
        //更新数据库
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("sku_id", skuId);
        wrapper.eq("user_id", oneOfUserId);
        baseMapper.update(cartInfo, wrapper);
        //更新缓存
        //a.从redis中查询数据并修改(主要为了学习)
        String userCartKey = getUserCartKey(oneOfUserId);
        BoundHashOperations boundHashOps = redisTemplate.boundHashOps(userCartKey);
        //从hash里面根据skuId拿到购物车商品sku信息
        if (boundHashOps.hasKey(skuId.toString())) {
            CartInfo redisCartInfo = (CartInfo) boundHashOps.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //更新到redis中
            boundHashOps.put(skuId.toString(), redisCartInfo);
            //设置过期时间
            setCartKeyExpire(userCartKey);
        }
    }

    @Override
    public void deleteCart(String oneOfUserId, Long skuId) {
        //删redis
        //a.先删除redis里面的内容
        String userCartKey = getUserCartKey(oneOfUserId);
        BoundHashOperations boundHashOps = redisTemplate.boundHashOps(userCartKey);
        if (boundHashOps.hasKey(skuId.toString())) {
            boundHashOps.delete(skuId.toString());
        }
        //删除数据库
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        wrapper.eq("sku_id", skuId);
        baseMapper.delete(wrapper);
    }

    @Override
    public List<CartInfo> getSelectedCartInfo(String userId) {
        String userCartKey = getUserCartKey(userId);
        List<CartInfo> cartInfoRedis = redisTemplate.opsForHash().values(userCartKey);
        if (CollectionUtils.isEmpty(cartInfoRedis)) {
            QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId);
            cartInfoRedis = baseMapper.selectList(wrapper);
        }
        List<CartInfo> selectedCartInfoList = new ArrayList<>();
        for (CartInfo cartInfo : cartInfoRedis) {
            if (cartInfo.getIsChecked() == 1) {
                selectedCartInfoList.add(cartInfo);
            }
        }
        return selectedCartInfoList;
    }

    private List<CartInfo> deleteNoLoginDataAndReload(String userId, String userTempId) {
        //合并用删除 临时数据
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userTempId);
        baseMapper.delete(wrapper);
        //删除，临时缓存，userId混村
        String userTempCartKey = getUserCartKey(userTempId);
        String userCartKey = getUserCartKey(userId);
        redisTemplate.delete(userTempCartKey);
        redisTemplate.delete(userCartKey);

        //重新加载到redis
        return queryDataFromCash(userId);

    }

    private CartInfo getCartInfoFromDb(String oneOfUserId, Long skuId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("sku_id", skuId);
        wrapper.eq("user_id", oneOfUserId);
        return baseMapper.selectOne(wrapper);
    }

    private void margeCartInfo(String userId, String userTempId) {
        List<CartInfo> noLoginCartInfo = queryDataFromCash(userTempId);
        List<CartInfo> loginCartInfo = queryDataFromCash(userId);

        Map<Long, CartInfo> loginCartInfoMap = loginCartInfo.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo ->
                cartInfo));
        for (CartInfo noCartInfo : noLoginCartInfo) {
            if (loginCartInfoMap.containsKey(noCartInfo.getSkuId())) {
                CartInfo cartInfo = loginCartInfoMap.get(noCartInfo.getSkuId());
                //说明 临时和userId
                cartInfo.setSkuNum(cartInfo.getSkuNum() + noCartInfo.getSkuNum());
                //临时 的购物车,userId的购物车  交集的话 isCheck=true
                if (cartInfo.getIsChecked() == 0) {
                    cartInfo.setIsChecked(1);
                }
                //修改购物车
                baseMapper.updateById(cartInfo);
                //删除
            } else {
                //没有交集,进行添加
                noCartInfo.setUserId(userId);
                baseMapper.updateById(noCartInfo);
            }
        }
    }
        //for (CartInfo nocCartInfo : noLoginCartInfo) {
        //    for (CartInfo cartInfo : loginCartInfo) {
        //        if(nocCartInfo.getSkuId().equals(cartInfo.getSkuId())){
        //            //说明 临时和userId
        //            cartInfo.setSkuNum(cartInfo.getSkuNum()+nocCartInfo.getSkuNum());
        //            //临时 的购物车,userId的购物车  交集的话 isCheck=true
        //            if(cartInfo.getIsChecked()==0) {
        //                cartInfo.setIsChecked(1);
        //            }
        //            //修改购物车
        //            baseMapper.updateById(cartInfo);
        //            //删除
        //        }else {
        //            //没有交集,进行添加
        //            nocCartInfo.setUserId(userId);
        //            baseMapper.updateById(nocCartInfo);
        //        }
        //    }
        //}
    private List<CartInfo> queryDataFromDb(String oneOfUserId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        return baseMapper.selectList(wrapper);
    }

    private void setCartKeyExpire(String userCartKey) {
        redisTemplate.expire(userCartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    private String getUserCartKey(String userTempId) {
        String userCartKey = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
        return userCartKey;
    }

    private List<CartInfo> queryDataFromCash(String oneOfUserId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
            //先去查redis
            String userCartKey = getUserCartKey(oneOfUserId);
            cartInfoList = redisTemplate.boundHashOps(userCartKey).values();
            //查数据库
            if (CollectionUtils.isEmpty(cartInfoList)) {
                cartInfoList=queryDataFromDb(oneOfUserId);
                //放入缓存
                Map<String, CartInfo> cartMap = new HashMap<>();
                for (CartInfo cartInfo : cartInfoList) {
                    cartMap.put(cartInfo.getSkuId().toString(), cartInfo);
                }
                redisTemplate.boundHashOps(userCartKey).putAll(cartMap);
                setCartKeyExpire(userCartKey);
            }

        return cartInfoList;
    }
}
